﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Objects;
using MShop.Core.Domain;
using MShop.Core.Util;
using System.Linq.Expressions;
using System.Collections;

namespace MShop.Core.DataAccess
{
    
    public class CommonDao<T> : ICommonDao<T> where T: class,System.Data.Objects.DataClasses.IEntityWithKey
    {
        private IObjectContextProvider _provider;
        public CommonDao(IObjectContextProvider provider)
        {
            _provider = provider;
        }
        

        public virtual IQueryable<T> GetAll()
        {
            return this.ObjectContext.CreateObjectSet<T>();
        }

        public virtual IQueryable<T> Find(System.Linq.Expressions.Expression<Func<T, bool>> expr)
        {
            return this.ObjectContext.CreateObjectSet<T>().Where(expr);
        }

        public virtual void Save(T entity)
        {
            this.ObjectContext.CreateObjectSet<T>().AddObject(entity);
          
        }

        public virtual void Delete(T entity)
        {
            this.ObjectContext.DeleteObject((object)entity);
           
        }

        public virtual void Delete(object obj)
        {
            if (obj is IEnumerable)
            {
                ArrayList al = new ArrayList();
               var enumerator=  (obj as IEnumerable).GetEnumerator();
               while (enumerator.MoveNext())
               {
                   if (enumerator.Current is System.Data.Objects.DataClasses.IEntityWithKey)
                   {
                       al.Add(enumerator.Current);
                   }
               }

               foreach (object item in al)
               {
                   this.ObjectContext.DeleteObject(item);
               }
            }
            else
            {
                if (obj is System.Data.Objects.DataClasses.IEntityWithKey)
                {
                    this.ObjectContext.DeleteObject(obj);
                }
            }
            
        }

        public virtual void Update(T entity)
        {
            
        }

        public virtual T GetById(object oid)
        {
            string quilifiedEntitySetName = "MShopEntities";
            quilifiedEntitySetName=this.ObjectContext.DefaultContainerName;
            EntityKey key = new EntityKey(quilifiedEntitySetName + "." + typeof(T).Name, PrimaryKey, oid);
            object entity = null;
            this.ObjectContext.TryGetObjectByKey(key, out entity);
            return entity as T;
        }

        public virtual T Get(System.Linq.Expressions.Expression<Func<T, bool>> expr)
        {
            return  this.ObjectContext.CreateObjectSet<T>().FirstOrDefault(expr);
        }


        public virtual IQueryable<T> Find(string query, params System.Data.Objects.ObjectParameter[] parameter)
        {
            return this.ObjectContext.CreateQuery<T>(query, parameter);
        }





        public virtual int SaveChanges()
        {
           return  _provider.ObjectContext.SaveChanges();
        }



        public virtual ObjectContext ObjectContext
        {
            get { return _provider.ObjectContext; }
        }

        public virtual IQueryable<T> Page<Tkey>(int pageSize, int pageIndex, Sort sort, Expression<Func<T, bool>> expr, Expression<Func<T, Tkey>> keySelector, out int totalItemCount)
        {
            var query = this.ObjectContext.CreateObjectSet<T>();

            totalItemCount = query.Count(expr);

            int skipItemCount= pageSize * pageIndex ;
            switch (sort)
            {
                case Sort.Ascending:
                    query.Where(expr).OrderBy(keySelector).Take(pageSize)
                      .Skip(skipItemCount);
                    break;
                case Sort.Descending:
                    query.Where(expr).OrderByDescending(keySelector).Take(pageSize)
                    .Skip(skipItemCount);
                    break;
            }         
            return query;

        }



      

        public void Save(object entity)
        {
            this.Save((T)entity);
        } 


        public void Update(object entity)
        {
            this.Update((T)entity);
        }





        public virtual T FirstOrDefault()
        {
            return FirstOrDefault(null);
              
        }

        public virtual T FirstOrDefault(Expression<Func<T, bool>> expr)
        {
            if (expr == null)
            {
                return GetAll().FirstOrDefault();
            }
            else
            {
                return Find(expr).FirstOrDefault();
            }
        }



        #region ICommonDao<T> Members

        protected string _PrimaryKey = "Id";
        public string PrimaryKey
        {
            get
            {
                return _PrimaryKey;
            }
            set
            {
                _PrimaryKey = value;
            }
        }

        #endregion
    }
}
